﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;

namespace HypermarketSerialPort._1_Model
{
    class AddTransactionManager
    {
        static private string MSG_PRODUCT_NOT_FOUND = "Sorry, this product currently is not availiable!";
        static private string MSG_NOTENOUGH_QUANTITY = "This product is short of demand, only left ";
        static private string MSG_QUANTITY_ERROR = "Please type in valid quantity!";
        static private string MSG_SCANNED = "Scanned item";

        static private int MIN_DISCOUNT = 0;
        static private int MIN_QUALITY = 0;
        static private int MIN_ROW_COUNT = 0;

        private static AddTransactionManager mInstance;
        private DBManager mDBManager;

        private Dictionary<string, string> mTransactionIDList = new Dictionary<string, string>();

        #region AddTransactionManager
        //only create one instance of CheckInforManager
        public static AddTransactionManager getInstance()
        {
            if (mInstance == null)
            {
                mInstance = new AddTransactionManager();
            }
            return mInstance;
        }
        #endregion


        #region Constructor
        private AddTransactionManager()
        {
            mDBManager = DBManager.getInstance();
            DataTable Transaction = mDBManager.getTable(Constant.TRANSACTION_TABLE);
            foreach (DataRow dr in Transaction.Rows)
            {
                string id = dr[Constant.TRANSACTION_ID].ToString();
                mTransactionIDList.Add(id, id);
            } 
        }
        #endregion


        #region Operation for adding transactions
        public string OperationAddTransaction(List<string> receivedInfoList, Dictionary<string, CashierRegister> cashierDict)
        {
            if (receivedInfoList.Count() == Constant.THREE)
            { 
                string productID = receivedInfoList[Constant.ONE];
                string quantity = receivedInfoList[Constant.TWO];
                string machineID = receivedInfoList[Constant.ZERO];
                // check machier ID valid
                CashierRegister cashierRegister;
                if (cashierDict.TryGetValue(machineID, out cashierRegister))
                {
                    if (!cashierRegister.isTransactionStarted())
                    {
                        string transactionID = GenerateNextTransactionID();
                        cashierRegister.StartTransaction(transactionID);
                    }
                    return AddTransactionInfo(productID, quantity, cashierRegister, machineID);
                }
                else
                {
                    return Constant.LOGIN_FIRST_MSG;
                }
            }
            else
            {
                return Constant.PROGRAM_ERROR;
            }
        }
        #endregion 


        #region Add Transaction
        private string AddTransactionInfo(string productID, string quantity, CashierRegister cashierRegister, string machineID)
        {
            // TO CHECK 
            if (Convert.ToInt16(quantity) <= MIN_QUALITY)
                return MSG_QUANTITY_ERROR;

            DataRow[] discountRows = GetDiscountProductDataRows(productID);
            if (discountRows.Count() == MIN_ROW_COUNT)
            {
                //select from stock table only, no discount for this product
                return NoDiscount(productID, quantity, cashierRegister, machineID);
            }
            else if (Convert.ToInt16(discountRows.First()[Constant.QUANTITY]) < Convert.ToInt16(quantity))
            {
                return MSG_NOTENOUGH_QUANTITY + discountRows.First()[Constant.QUANTITY].ToString();
            }
            else
            {
                return HaveDiscount(productID, quantity, discountRows.First(), cashierRegister, machineID);
            }
        }

        #region Has Discount
        private DataRow[] GetDiscountProductDataRows(string productID)
        {
            DataTable StockProductDiscount = mDBManager.getTable(Constant.STOCK_PRODUCT_DISCOUNT_TABLE);
            string query = Constant.PRODUCT_ID + Constant.EQUAL + Constant.SINGAL_QUOTE + productID +
                    Constant.SINGAL_QUOTE + Constant.AND + Constant.EXPIRE_DATE + Constant.MORE_THAN +
                    Constant.SINGAL_QUOTE + DateTime.Today + Constant.SINGAL_QUOTE;
            DataRow[] discountRows = StockProductDiscount.Select(query);  //query add barcode, batchID, costprice
            return discountRows;
        }

        private static string HaveDiscount(string productID, string quantity, DataRow dr, CashierRegister cashierRegister, string machineID)
        {
            if (Convert.ToInt16(quantity) < Convert.ToInt16(dr[Constant.BUNDLE_UNIT]))
            {
                string name = dr[Constant.NAME].ToString();
                string sellingPrice = dr[Constant.SELLING_PRICE].ToString();
                string batchID = dr[Constant.BATCH_ID].ToString();
                string importPrice = dr[Constant.IMPORT_PRICE].ToString();

                cashierRegister.AddTransaction(productID, name, batchID, importPrice, sellingPrice, Constant.ZERO_PERCENTAGE, Convert.ToInt16(quantity)); //for database report purpose
                string output = MSG_SCANNED + Constant.COLON + Constant.NEWLINE + Constant.PRODUCT_ID + Constant.COLON + Constant.SPACE + productID 
                                + Constant.SPACE + name + Constant.NEWLINE + Constant.SELLING_PRICE + Constant.COLON + Constant.SPACE + 
                                Math.Round(Convert.ToDecimal(sellingPrice), Constant.TWO) + Constant.NEWLINE /***sound index****/;
                return output;
            }
            else if ((Convert.ToInt16(dr[Constant.FREE_ITEM_QUANTITY]) > MIN_DISCOUNT) || (Convert.ToInt16(dr[Constant.DISCOUNT]) > MIN_DISCOUNT))
            {
                return AddDiscountTransaction(productID, quantity, dr, cashierRegister, machineID);
            }
            else
            {
                return Constant.PROGRAM_ERROR;
            }
        }

        private static string AddDiscountTransaction(string productID, string quantity, DataRow dr, CashierRegister cashierRegister, string machineID)
        {
            string name = dr[Constant.NAME].ToString();
            double sellingPrice = Convert.ToDouble(dr[Constant.SELLING_PRICE]);
            string batchID = dr[Constant.BATCH_ID].ToString();
            string importPrice = dr[Constant.IMPORT_PRICE].ToString();
            double BuPrice = (sellingPrice * Convert.ToInt16(quantity)) / (Convert.ToInt16(quantity) + Convert.ToInt16(dr[Constant.FREE_ITEM_QUANTITY]));
            double finalPrice = BuPrice * (100 - Convert.ToInt16(dr[Constant.DISCOUNT])) / 100;
            double discount = 100 - (finalPrice / sellingPrice) * 100;
            cashierRegister.AddTransaction(productID, name, batchID, importPrice, sellingPrice.ToString(), discount.ToString(), Convert.ToInt16(quantity)); //for database report purpose 
            string output = MSG_SCANNED + Constant.COLON + Constant.NEWLINE + Constant.PRODUCT_ID + Constant.COLON + Constant.SPACE + productID + Constant.NEWLINE + 
                            Constant.NAME + Constant.COLON + Constant.SPACE + name + Constant.NEWLINE + Constant.SELLING_PRICE + Constant.COLON + Constant.SPACE + 
                            Math.Round(Convert.ToDecimal(finalPrice), Constant.TWO) + Constant.NEWLINE + Constant.QUANTITY + Constant.COLON + Constant.SPACE + quantity + Constant.NEWLINE/***sound index****/;
            return output;
        }
        #endregion

        #region No Discount
        private string NoDiscount(string productID, string quantity, CashierRegister cashierRegister, string machineID)
        {
            DataRow[] rows = GetNoDiscountProductDataRows(productID);
            if (rows.Count() == MIN_QUALITY)
            {
                return MSG_PRODUCT_NOT_FOUND;
            }
            else if (Convert.ToInt16(rows.First()[Constant.QUANTITY]) < Convert.ToInt16(quantity))
            {
                return MSG_NOTENOUGH_QUANTITY + rows.First()[Constant.QUANTITY].ToString();
            }
            else
            {
                return AddNoDiscountTransaction(productID, quantity, cashierRegister, machineID, rows.First());
            }
        }

        private DataRow[] GetNoDiscountProductDataRows(string productID)
        {
            DataTable Stock = mDBManager.getTable(Constant.STOCK_PRODUCT_TABLE);
            string query = Constant.PRODUCT_ID + Constant.EQUAL + Constant.SINGAL_QUOTE + productID +
                    Constant.SINGAL_QUOTE + Constant.AND + Constant.EXPIRE_DATE + Constant.MORE_THAN +
                    Constant.SINGAL_QUOTE + DateTime.Today + Constant.SINGAL_QUOTE;
            DataRow[] rows = Stock.Select(query);
            return rows;
        }

        private static string AddNoDiscountTransaction(string productID, string quantity, CashierRegister cashierRegister, string machineID, DataRow dr)
        {
            string name = dr[Constant.NAME].ToString();
            string sellingPrice = dr[Constant.SELLING_PRICE].ToString();
            string batchID = dr[Constant.BATCH_ID].ToString();
            string importPrice = dr[Constant.IMPORT_PRICE].ToString();

            cashierRegister.AddTransaction(productID, name, batchID, importPrice, sellingPrice, Constant.ZERO_PERCENTAGE, Convert.ToInt16(quantity)); //for database report purpose
            string output = MSG_SCANNED + Constant.COLON + Constant.NEWLINE + Constant.PRODUCT_ID + Constant.COLON + Constant.SPACE + productID + Constant.NEWLINE + 
                            Constant.NAME + Constant.COLON + Constant.SPACE + name + Constant.NEWLINE + Constant.SELLING_PRICE + Constant.COLON + Constant.SPACE + 
                            Math.Round(Convert.ToDecimal(sellingPrice), Constant.TWO) + Constant.NEWLINE + Constant.QUANTITY + Constant.COLON + Constant.SPACE + quantity + Constant.NEWLINE  /***sound index****/;
            return output;
        }
        #endregion 
        #endregion 


        #region Generate next Transaction ID
        private string GenerateNextTransactionID()
        {
            int id = int.Parse(mTransactionIDList.Last().Value) + Constant.ONE;
            mTransactionIDList.Add(id.ToString(), id.ToString());
            return id.ToString();
        }
        #endregion 
       

    }
}

